/*
 * MessageCodec.cpp
 * 
 * Protobuf 消息编解码器实现
 */

#include "MessageCodec.h"
#include <muduo/base/Logging.h>
#include <arpa/inet.h>  // htonl, ntohl

using namespace muduo;
using namespace muduo::net;

namespace protocol {

void MessageCodec::encode(uint16_t msgId,
                         const google::protobuf::Message& message,
                         Buffer* buf) {
    // 序列化 Protobuf 消息
    std::string data;
    if (!message.SerializeToString(&data)) {
        LOG_ERROR << "Failed to serialize protobuf message";
        return;
    }
    
    // 构造包头
    PacketHeader header;
    header.setLength(PacketHeader::kHeaderSize + data.size());
    header.setMsgId(msgId);
    
    // 写入包头（注意字节序）
    buf->appendInt32(header.getLength());  // muduo Buffer 自动处理字节序
    buf->appendInt16(header.getMsgId());
    buf->appendInt16(header.flags);
    buf->appendInt32(header.reserved1);
    buf->appendInt32(header.reserved2);
    
    // 写入数据
    buf->append(data.data(), data.size());
}

int MessageCodec::decode(Buffer* buf, uint16_t& msgId, std::string& data) {
    // 检查是否有完整的包头
    if (buf->readableBytes() < PacketHeader::kHeaderSize) {
        return 0;  // 包头不完整
    }
    
    // 读取包头（使用 peek，不移动 readerIndex）
    const void* headerData = buf->peek();
    PacketHeader header;
    
    // 手动解析包头（注意字节序转换）
    const char* p = static_cast<const char*>(headerData);
    
    // 读取 length（4 字节，网络字节序）
    uint32_t length;
    memcpy(&length, p, sizeof(uint32_t));
    header.setLength(ntohl(length));  // 网络序转主机序
    p += sizeof(uint32_t);
    
    // 读取 msgId（2 字节）
    uint16_t msg_id;
    memcpy(&msg_id, p, sizeof(uint16_t));
    header.setMsgId(ntohs(msg_id));
    p += sizeof(uint16_t);
    
    // 读取 flags（2 字节）
    memcpy(&header.flags, p, sizeof(uint16_t));
    header.flags = ntohs(header.flags);
    p += sizeof(uint16_t);
    
    // 读取保留字段
    memcpy(&header.reserved1, p, sizeof(uint32_t));
    header.reserved1 = ntohl(header.reserved1);
    p += sizeof(uint32_t);
    
    memcpy(&header.reserved2, p, sizeof(uint32_t));
    header.reserved2 = ntohl(header.reserved2);
    
    // 验证包头
    if (!checkHeader(header)) {
        LOG_ERROR << "Invalid packet header: length=" << header.getLength();
        return -1;  // 包头错误
    }
    
    // 检查是否有完整的数据包
    if (buf->readableBytes() < header.getLength()) {
        return 0;  // 数据不完整
    }
    
    // 跳过包头
    buf->retrieve(PacketHeader::kHeaderSize);
    
    // 读取数据部分
    size_t dataSize = header.getLength() - PacketHeader::kHeaderSize;
    data.assign(buf->peek(), dataSize);
    buf->retrieve(dataSize);
    
    // 返回消息ID
    msgId = header.getMsgId();
    
    return header.getLength();
}

bool MessageCodec::checkHeader(const PacketHeader& header) {
    // 检查长度是否合法
    if (header.getLength() < PacketHeader::kMinPacketSize) {
        return false;
    }
    
    if (header.getLength() > PacketHeader::kMaxPacketSize) {
        return false;
    }
    
    return true;
}

} // namespace protocol

